package javabasics.netty.demo2;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @Author suxiaoxiao
 * @Date 2019/9/16 1:44
 * @Version 1.0
 */
public class NettyClient {

    public static final int MAX_RETRY = 5;

    public static void main(String[] args) {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap
                // 指定线程组
                .group(workerGroup)
                // 指定 IO 模型为 NIO
                .channel(NioSocketChannel.class)
                // 超时时间
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                // TCP 心跳机制
                .option(ChannelOption.SO_KEEPALIVE, true)
                // Nagle算法
                .option(ChannelOption.TCP_NODELAY, true)
                // IO 处理逻辑
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) {
                        socketChannel
                                // 返回的是和这条连接相关的逻辑处理链，责任链模式。
                                .pipeline()
                                // 添加一个逻辑处理器（自定义）
                                .addLast(new FirstClientHandler());
                    }
                });

        connect(bootstrap, "localhost", 8090, MAX_RETRY);

    }

    /**
     * 失败重连机制
     * @param bootstrap
     * @param host
     * @param port
     */
    private static void connect(Bootstrap bootstrap, String host, int port, int retry) {
        bootstrap.connect(host, port).addListener(future -> {
            if (future.isSuccess()) {
                System.out.println("连接成功！");
            } else if (retry == 0) {
                System.out.println("重试次数已用完，放弃连接！");
            } else {
                // 第几次重连
                int order = (MAX_RETRY - retry) + 1;
                // 本次重连的间隔
                int delay = 1 << order;
                System.out.println(new Date() + "：连接失败，第" + order + "次重连......");
                bootstrap.config().group()
                        // 定时任务
                        .schedule(() -> connect(bootstrap, host, port + 1, retry - 1), delay, TimeUnit.SECONDS);
            }
        });
    }

}
